package com.sfc.sdsr.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.Properties;

import org.apache.log4j.Logger;

import com.sfc.sdsr.common.GZipUtil;
import com.sfc.sdsr.server.commands.CommandFactory;
import com.sfc.sdsr.server.commands.Command;

public class RequestHandler implements Runnable {

	private final Logger log = Logger.getLogger(getClass());
	
	private Socket socket;
	
	public RequestHandler(Socket socket, Properties properties) {
		this.socket = socket;
	}

	@Override
	public void run() {
		try {
			InputStream is = socket.getInputStream();
			byte[] streamSizeBytes = new byte[4];
			is.read(streamSizeBytes);
			byte operation = (byte) is.read();
			int streamSize = ByteBuffer.wrap(streamSizeBytes).getInt();

			byte[] gZipData = new byte[streamSize];
			int readBytes = is.read(gZipData);

			log.debug("Checking that the bytes read equals the stream size " + readBytes + " vs " + streamSize);

			byte[] data = GZipUtil.decompress(gZipData);

			ClientData clientData = new ClientData(data, operation);

			if (clientData.getOperationParameter() != null) {
				log.debug(" =======>>>>> " + clientData.getOperationParameter().getClass());
			} else {
				log.debug(" =======>>>>> " + clientData.getOperationParameter());
			}
			
			// the actual type of the operation parameter won't be checked until the command level
			
			Command command = CommandFactory.getCommand(clientData);
			command.proxyExecute();

			byte[] compressedBytes = GZipUtil.compress(command.serializeReturn());
			
			OutputStream os = socket.getOutputStream();
			
			os.write(ByteBuffer.allocate(4).putInt(compressedBytes.length).array());
			os.write(compressedBytes);

		} catch (IOException ioe) {
			log.error("IOException: " + ioe.getMessage(), ioe);
		} finally {
		    if (socket != null) {
		        try {
		            log.info("Closing socket, ending thread");
		            socket.close();
		        } catch (IOException ioe) {
		            log.error("Failed to close socket: " + ioe.getMessage(), ioe);
		        }
		    }
		}
	}

}
